package org.lemma.number;

import static org.lemma.number.Natural.ZERO;
import static org.lemma.number.Natural.ONE;
import java.io.Serializable;
import javax.annotation.Author;
import javax.annotation.Copyright;
import javax.annotation.Version;

/**
 * <p>
 * A <dfn>Complex Number</dfn> is a {@linkplain Numeric number} of the form:
 * <dfn>a + bi</dfn>, where <i>a</i> and <i>b</i> are {@linkplain Real real
 * numbers} and <i>i</i> is the imaginary number.
 * </p>
 * <p>
 * Given a complex number, <dfn>z = a + bi</dfn>, the <i>real</i> part of the
 * complex number is &real;(<i>z</i>) = <i>a</i> and the <i>imaginary</i>
 * part of the complex number is &image;(<i>z</i>) = <i>b</i>.
 * </p>
 * <div class="references">
 *  <cite>
 *  "Complex number." <i>Wikipedia, The Free Encyclopedia</i>.
 *  17 Aug 2007, 14:46 UTC. Wikimedia Foundation, Inc.  20 Aug 2007
 *  <a href="http://en.wikipedia.org/w/index.php?title=Complex_number&amp;oldid=151832391">
 *  http://en.wikipedia.org/w/index.php?title=Complex_number&amp;oldid=151832391</a>
 *  </cite>
 * </div>
 *
 * @author Chris Beatty [christopher.beatty@gmail.com]
 * @version 1.0.0
 */
@Version (
    major="1", minor="0", patch="0", 
    date="Jun 16, 2008 1:59:18 PM",
    authors = {
        @Author (name="Chris Beatty", email="christopher.beatty@gmail.com")
    }
) @Copyright 
public class Complex implements Numeric, Serializable {

    /**
     * Determines if a de-serialized file is compatible with this class.
     *
     * Maintainers must change this value if and only if the new version
     * of this class is not compatible with old versions. See Sun docs
     * for <a href="http://java.sun.com/products/jdk/1.1/docs/guide
     * /serialization/spec/version.doc.html">details.</a>
     */
    private static final long serialVersionUID = 1L;   
    
    /**
     * Unicode character for the imaginary number
     */
    private static final char UNICODE_IMAGINARY = '\u2148';   
    
    /**
     * Constant for <dfn>i</dfn> (i.e., 0 + 1<i>i</i>)
     */
    public static final Complex i = new Complex(ZERO, ONE);
    
    /**
     * The real part of this complex number as a {@linkplain Real real number}
     */
    private Real realPart = ZERO;
    
    /**
     * The imaginary part of this complex number as a {@linkplain Real real number}
     */    
    private Real imaginaryPart = ZERO;
    
    /**
     * Default Class Constructor
     * Creates and initializes a new instance of {@code Complex}
     */
    protected Complex() {
        this(ZERO, ZERO);
    }
    
    /**
     * Class constructor
     * Creates a new instance of {@code Complex} and initializes its
     * real and imaginary parts
     * 
     * @param rePart A {@linkplain Real real number}
     * @param imPart A {@linkplain Real real number}
     */
    public Complex(Real rePart, Real imPart) {
        if(rePart != null && imPart != null) {
            this.realPart = rePart;
            this.imaginaryPart = imPart;
        } else {
            throw new IllegalArgumentException("Null value provided");
        }
    }
    
    /**
     * Accessor method for the real part of this complex number
     * 
     * @return A {@linkplain Real real number}
     */
    public Real realPart() {
        return this.realPart;
    }
    
    /**
     * Accessor method for the imaginary part of this complex number
     * 
     * @return A {@linkplain Real real number}
     */    
    public Real imaginaryPart() {
        return this.imaginaryPart;
    }
    
    /**
     * {@inheritDoc}
     *
     * The sign for a complex number is based on the complex signum function, 
     * <dfn>csgn</dfn>, as defined by:
     * <table class="function">
     *  <tr class="definition">
     *      <td class="name" rowspan="4">csgn(z)</td>
     *  </tr>
     *  <tr class="case">
     *      <td class="value">1</td>
     *      <td class="condition">&real;(<i>z</i>) > 0 &or; (&real;(<i>z</i>) = 0 &and; &image;(<i>z</i>) > 0)</td>
     *  </tr>
     *  <tr class="case">
     *      <td class="value">-1</td>
     *      <td class="condition">&real;(<i>z</i>) < 0 &or; (&real;(<i>z</i>) = 0 &and; &image;(<i>z</i>) < 0)</td>
     *  </tr>
     *  <tr class="case">
     *      <td class="value">0</td>
     *      <td class="condition">&real;(<i>z</i>) = &image;(<i>z</i>) = 0</td>
     *  </tr>
     * </table>
     *
     * @return {@inheritDoc}
     */    
    public Sign sign() {
        Sign reSign = this.realPart.sign();
        Sign imSign = this.imaginaryPart.sign();

        if ((reSign == Sign.None) && (imSign == Sign.None)) {
            return Sign.None;
        } else if ((reSign == Sign.Positive) || (reSign == Sign.Negative)) {
            return reSign;
        } else {
            return imSign;
        }        
    }
    
    /**
     * {@inheritDoc}
     * 
     * @return {@inheritDoc}
     */
    @Override 
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.realPart.toString());
        sb.append(this.imaginaryPart.sign().toString());
        sb.append(this.imaginaryPart.toString());
        sb.append(UNICODE_IMAGINARY);
        return sb.toString();
    }

}
